/**
 * @author 木人心
 * @version 1.2.0
 */
import { RouteLocationNamedRaw, RouteLocationNormalized, Router } from 'vue-router'
import Authorization from '@utils/authorization'
import { decrypt, encrypt } from '@utils/crypto'

export default class Security {
  // 路由实例
  private static toRoute: RouteLocationNormalized

  // 授权结果
  private static isAuthorized: boolean = null

  // 匹配结果
  private static isMatching = false

  static init (toRoute: RouteLocationNormalized) {
    this.toRoute = toRoute
    this.isAuthorized = null
    this.isMatching = false
    return this
  }

  /**
   * 检查匹配项是否符合路由地址
   * @param pathTag
   * @private
   */
  private static checkPathTag (pathTag: string) {
    return new RegExp(pathTag
      .replace(/\/\*\*/g, '(/.*)')
      .replace(/\/\*/g, '(/((?!/).)*)') + '$')
      .test(this.toRoute.path)
  }

  /**
   * 定义匹配项
   * @param matchers
   */
  static antMatchers (matchers: string[]) {
    this.isMatching = false
    for (let i = 0, len = matchers.length; i < len; i++) {
      if (this.checkPathTag(matchers[i])) {
        this.isMatching = true
        break
      }
    }
    return this
  }

  /**
   * 匹配所有请求
   */
  static anyRequest () {
    this.isMatching = true
    return this
  }

  /**
   * 许可【所有请求】
   */
  static permitAll () {
    if (this.isAuthorized !== null) return this
    if (this.isMatching) {
      this.isAuthorized = true
    }
    return this
  }

  /**
   * 许可【认证】的请求
   */
  static authenticated () {
    if (this.isAuthorized !== null) return this
    if (this.isMatching) {
      this.isAuthorized = Authorization.isAuthenticated
    }
    return this
  }

  /**
   * 许可【authorizedCheck校验】的请求，根据路由自身的权限校验
   */
  static authorizedCheck () {
    if (this.isAuthorized !== null) return this
    if (this.isMatching) {
      const { permission = '', role = [] } = this.toRoute.meta
      this.isAuthorized = Authorization.authorizedCheck(permission, role)
    }
    return this
  }

  /**
   * 获取结果
   */
  static getResult () {
    return {
      // 授权
      isAuthorized: this.isAuthorized,
      // 认证
      isAuthenticated: Authorization.isAuthenticated
    }
  }
}

/**
 * 参数加密
 * @param router
 */
export function queryEncrypt (router: Router) {
  (['push', 'replace']).forEach(function (key) {
    const original = router[key]
    router[key] = function (to: Parameters<typeof router.push>[0]) {
      let _to = to
      if (typeof to !== 'string' && (to?.query || (to as RouteLocationNamedRaw)?.params)) {
        _to = { query: {}, params: {}, ...to }
        const queryKeyLen = Object.keys(_to.query).length || Object.keys(_to.params).length
        // 如果有需要加密的内容
        if (queryKeyLen) {
          // 如果不是已经加密过的
          if (!(_to.query.v && queryKeyLen === 1)) {
            _to.query = {
              v: encrypt(JSON.stringify({
                query: _to.query,
                params: _to.params
              }))
            }
          }
        }
      }
      return original.call(this, _to)
    }
  })
}

/**
 * 参数解密
 * @param to
 */
export function queryDecrypt (to: RouteLocationNormalized) {
  if (to.query.v) {
    const { params, query } = JSON.parse(decrypt(to.query.v as string))
    to.query = query || {}
    to.params = params || {}
  }
}

/**
 * 获取加密的路由参数
 * 示例：
 * window.open('/#/xxx?v=' + getEncryptVStr({ ... }))
 * @param params
 */
export function getEncryptVStr (params: { query?: Record<string, any>, params?: Record<string, any> }) {
  const _params = { query: {}, params: {}, ...params }
  return encodeURIComponent(encrypt(JSON.stringify(_params)))
}
